package org.domon.attendance;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.swing.JButton;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SuppressWarnings("serial")
public class MainFrame extends JFrame {

	private static final Logger logger = LoggerFactory
			.getLogger(MainFrame.class);

	private JTextField textField;

	private JTextField sTextField;

	private JTextField eTextField;

	// 月初日期
	private Date sDate;
	// 月末日期
	private Date eDate;

	// 上班时间
	private JTextField sTimeTextField;
	// 下班时间
	private JTextField eTimeTextField;
	// 加班时间
	private JTextField oTimeTextField;

	// 上班时间
	private String sTimeStr;
	// 下班时间
	private String eTimeStr;
	// 加班时间
	private String oTimeStr;

	// 休息日
	private JTextField restTextField;
	// 工作日
	private JTextField workTextField;

	/**
	 * 每个人的打卡信息，按ID分组
	 */
	private Map<String, List<Worker>> dataMap;

	/**
	 * Launch the application
	 * 
	 * @param args
	 */
	public static void main(String args[]) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				MainFrame frame = new MainFrame();
				frame.setVisible(true);
			}
		});
	}

	/**
	 * Create the frame
	 */
	public MainFrame() {
		super();
		setTitle("考勤表分析");
		setBounds(500, 200, 450, 300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// -----------------------第一行 start----------------------------
		final JButton button = new JButton();
		button.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				JFileChooser jFile = new JFileChooser();
				jFile.setMultiSelectionEnabled(true);// 设置文件多选
				jFile.setFileFilter(new FileNameExtensionFilter("Excel", "xls"));
				jFile.showDialog(jFile, "请选择");
				File[] source = jFile.getSelectedFiles();
				if (source != null) {
					StringBuffer sb = new StringBuffer();
					String strs = null;
					for (int i = 0; i < source.length; i++) {
						strs = source[i].getAbsolutePath() + ";";
						if (i == source.length - 1) {
							strs = source[i].getAbsolutePath();
						}
						sb.append(strs);
					}
					textField.setText(sb.toString());
				}
			}
		});
		button.setBounds(10, 10, 65, 20);
		button.setText("选择");
		getContentPane().add(button);

		textField = new JTextField();
		textField.setBounds(85, 10, 320, 20);
		getContentPane().add(textField);
		// -----------------------第一行 end----------------------------

		// -----------------------第二行 start----------------------------
		JLabel jLabel = new JLabel();
		jLabel.setBounds(10, 40, 65, 20);
		jLabel.setText("休息日：");
		getContentPane().add(jLabel);

		restTextField = new JTextField();
		restTextField.setBounds(85, 40, 320, 20);
		getContentPane().add(restTextField);

		jLabel = new JLabel();
		jLabel.setBounds(10, 60, 400, 20);
		jLabel.setText("（设置非礼拜天的休息日，格式：2013-10-1/2013-10-2/2013-10-3）");
		getContentPane().add(jLabel);
		// -----------------------第二行 end----------------------------

		// -----------------------第 三行 start----------------------------
		jLabel = new JLabel();
		jLabel.setBounds(10, 90, 65, 20);
		jLabel.setText("工作日：");
		getContentPane().add(jLabel);

		workTextField = new JTextField();
		workTextField.setBounds(85, 90, 320, 20);
		getContentPane().add(workTextField);

		jLabel = new JLabel();
		jLabel.setBounds(10, 110, 400, 20);
		jLabel.setText("（设置是礼拜天的工作日，格式：2013-9-31/2013-9-30）");
		getContentPane().add(jLabel);
		// -----------------------第三行 end----------------------------

		// -----------------------第四行 start----------------------------
		jLabel = new JLabel();
		jLabel.setBounds(10, 140, 110, 20);
		jLabel.setText("请输入月初日期：");
		getContentPane().add(jLabel);

		sTextField = new JTextField();
		sTextField.setBounds(120, 140, 70, 20);
		getContentPane().add(sTextField);

		jLabel = new JLabel();
		jLabel.setBounds(200, 140, 90, 20);
		jLabel.setText("例如：2013-1-1");
		getContentPane().add(jLabel);
		// -----------------------第四行 end----------------------------

		// -----------------------第五行 start----------------------------
		jLabel = new JLabel();
		jLabel.setBounds(10, 170, 110, 20);
		jLabel.setText("请输入月末日期：");
		getContentPane().add(jLabel);

		eTextField = new JTextField();
		eTextField.setBounds(120, 170, 70, 20);
		getContentPane().add(eTextField);

		jLabel = new JLabel();
		jLabel.setBounds(200, 170, 100, 20);
		jLabel.setText("例如：2013-1-31");
		getContentPane().add(jLabel);
		// -----------------------第五行 end----------------------------

		// -----------------------第六行 start----------------------------
		jLabel = new JLabel();
		jLabel.setBounds(10, 200, 65, 20);
		jLabel.setText("上班时间：");
		getContentPane().add(jLabel);

		sTimeTextField = new JTextField();
		sTimeTextField.setBounds(85, 200, 40, 20);
		sTimeTextField.setText("8:15");
		getContentPane().add(sTimeTextField);

		jLabel = new JLabel();
		jLabel.setBounds(150, 200, 65, 20);
		jLabel.setText("下班时间：");
		getContentPane().add(jLabel);

		eTimeTextField = new JTextField();
		eTimeTextField.setBounds(225, 200, 40, 20);
		eTimeTextField.setText("17:10");
		getContentPane().add(eTimeTextField);

		jLabel = new JLabel();
		jLabel.setBounds(290, 200, 65, 20);
		jLabel.setText("加班时间：");
		getContentPane().add(jLabel);

		oTimeTextField = new JTextField();
		oTimeTextField.setBounds(365, 200, 40, 20);
		oTimeTextField.setText("20:20");
		getContentPane().add(oTimeTextField);
		// -----------------------第六行 end----------------------------

		// -----------------------第六行 start----------------------------
		JButton button_1 = new JButton();
		button_1.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent e) {
				String sou = textField.getText().trim();
				String sDateStr = sTextField.getText().trim();
				String eDateStr = eTextField.getText().trim();
				sTimeStr = sTimeTextField.getText().trim();
				eTimeStr = eTimeTextField.getText().trim();
				oTimeStr = oTimeTextField.getText().trim();

				if (StringUtils.isBlank(sou) || StringUtils.isBlank(sDateStr)
						|| StringUtils.isBlank(eDateStr)
						|| StringUtils.isBlank(sTimeStr)
						|| StringUtils.isBlank(eTimeStr)
						|| StringUtils.isBlank(oTimeStr)) {
					JOptionPane.showMessageDialog(null,
							"请选择分析的Excel文件并输入日期时间！\n不能太懒了");
				} else {
					try {
						sDate = strToDate(sDateStr, "yyyy-M-d");
						eDate = strToDate(eDateStr, "yyyy-M-d");
						strToDate(sTimeStr, "H:m");
						strToDate(eTimeStr, "H:m");
						strToDate(oTimeStr, "H:m");
					} catch (ParseException e1) {
						logger.error("日期解析错误", e1);
						JOptionPane.showMessageDialog(null,
								"日期/时间写错鸟！\n不能瞎写撒！\n" + e1.getMessage());
						return;
					}

					Map<String, Object> map;

					String[] files = sou.split(";");
					for (int i = 0; i < files.length; i++) {
						map = parseExcel(files[i]);
						if (!Boolean.valueOf(map.get("flag").toString())) {
							JOptionPane.showMessageDialog(null, "Excel文件"
									+ files[i] + "-->"
									+ map.get("msg").toString());
							return;
						}
					}

					try {
						check();
						JOptionPane.showMessageDialog(null,
								"分析完成！\n用完了之后要感恩一分钟，切记切记！");
					} catch (ParseException e1) {
						logger.error("日期解析错误", e1);
						JOptionPane.showMessageDialog(null, "日期/时间不能瞎写撒！\n"
								+ e1.getMessage());
					} catch (IOException e1) {
						logger.error("生成Excel失败", e1);
						JOptionPane.showMessageDialog(null,
								"生成Excel失败，请联系谢同学！\n" + e1.getMessage());
					}
				}
			}
		});
		button_1.setText("分析");
		button_1.setBounds(180, 230, 60, 20);
		getContentPane().add(button_1);
		// -----------------------第六行 end----------------------------

		final JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 40, 180, 400);
		getContentPane().add(scrollPane);
	}

	/**
	 * @throws ParseException
	 * @throws IOException
	 * 
	 */
	private void check() throws ParseException, IOException {
		String fileName = dateToStr(sDate, "yyyy-M") + ".xls";
		ExcelUtil excelUtil = new ExcelUtil();
		excelUtil.createExcelStart();

		int rowNo = 1;
		for (Map.Entry<String, List<Worker>> entry : dataMap.entrySet()) {
			List<Worker> workerList = entry.getValue();
			Worker tempWork = workerList.get(0);
			// 一个人的打卡信息，按日期分组
			Map<String, List<Worker>> mm = new HashMap<String, List<Worker>>();
			for (Worker worker : workerList) {
				String dateStr = dateToStr(worker.getDate(), "yyyy-M-d");
				if (mm.get(dateStr) == null) {
					mm.put(dateStr, new ArrayList<Worker>());
				}
				mm.get(dateStr).add(worker);
			}

			Date indexDate = sDate;
			Date eDate1 = DateUtils.addDays(eDate, 1);
			while (!DateUtils.isSameDay(indexDate, eDate1)) {
				// 某一天的打卡记录
				List<Worker> ll = mm.get(dateToStr(indexDate, "yyyy-M-d"));

				if (!isWorkDay(indexDate)) {
					// 休息日
					if (ll != null && ll.size() > 0) {
						Date startDate = ll.get(0).getDate();
						Date endDate = ll.get(ll.size() - 1).getDate();
						logger.info(
								"员工[{}]休息日加班：{} ---> {}",
								new String[] {
										tempWork.getName(),
										dateToStr(startDate,
												"yyyy-M-d a h:mm:ss"),
										dateToStr(endDate, "yyyy-M-d a h:mm:ss") });

						excelUtil.writeExcel(rowNo++, ll.get(0), "休息日加班");
					}
				} else {
					if (ll == null || ll.size() == 0) {
						Worker tWork = new Worker();
						tWork.setDept(tempWork.getDept());
						tWork.setName(tempWork.getName());
						tWork.setId(tempWork.getId());
						tWork.setDate(strToDate(
								dateToStr(indexDate, "yyyy-M-d") + " 0:00:01", "yyyy-M-d H:mm:ss"));
						tWork.setCardNo(tempWork.getCardNo());
						logger.info("员工[{}]旷工：{}", tWork.getName(),
								dateToStr(indexDate, "yyyy-M-d"));
						
						tempWork.setStbNo("");
						excelUtil.writeExcel(rowNo++, tWork, "旷工");
					} else if (ll.size() == 1) {
						Worker tt = ll.get(0);
						Date noonDate = strToDate(
								dateToStr(indexDate, "yyyy-M-d ") + "12:00:00",
								"yyyy-M-d H:mm:ss");
						Date compOverDate = strToDate(
								dateToStr(indexDate, "yyyy-M-d") + " "
										+ oTimeStr, "yyyy-M-d H:mm");
						if (tt.getDate().getTime() < noonDate.getTime()) {
							logger.info("员工[{}]下午无记录：{}", tempWork.getName(),
									dateToStr(indexDate, "yyyy-M-d"));
							excelUtil.writeExcel(rowNo++, tt, "下午无记录");
						} else if (tt.getDate().getTime() > compOverDate
								.getTime()) {
							logger.info("员工[{}]上午无记录（加班）：{}",
									tempWork.getName(),
									dateToStr(indexDate, "yyyy-M-d"));
							excelUtil.writeExcel(rowNo++, tt, "上午无记录（加班）");
						} else {
							logger.info("员工[{}]上午无记录：{}", tempWork.getName(),
									dateToStr(indexDate, "yyyy-M-d"));
							excelUtil.writeExcel(rowNo++, tt, "上午无记录");
						}

					} else {
						Collections.sort(ll);
						// 上班时间
						Date compStartDate = strToDate(
								dateToStr(indexDate, "yyyy-M-d") + " "
										+ sTimeStr, "yyyy-M-d H:mm");
						Date startDate = ll.get(0).getDate();
						if (startDate.getTime() > compStartDate.getTime()) {
							logger.info("员工[{}]迟到：{}", ll.get(0).getName(),
									dateToStr(startDate, "yyyy-M-d a h:mm:ss"));

							excelUtil.writeExcel(rowNo++, ll.get(0), "迟到");
						}
						// 下班时间
						Date compEndDate = strToDate(
								dateToStr(indexDate, "yyyy-M-d") + " "
										+ eTimeStr, "yyyy-M-d H:mm");
						// 加班时间
						Date compOverDate = strToDate(
								dateToStr(indexDate, "yyyy-M-d") + " "
										+ oTimeStr, "yyyy-M-d H:mm");
						Date endDate = ll.get(ll.size() - 1).getDate();
						if (endDate.getTime() < compEndDate.getTime()) {
							logger.info("员工[{}]早退：{}", tempWork.getName(),
									dateToStr(endDate, "yyyy-M-d a h:mm:ss"));

							excelUtil.writeExcel(rowNo++,
									ll.get(ll.size() - 1), "早退");
						} else if (endDate.getTime() >= compOverDate.getTime()) {
							logger.info("员工[{}]加班：{}", tempWork.getName(),
									dateToStr(endDate, "yyyy-M-d a h:mm:ss"));

							excelUtil.writeExcel(rowNo++,
									ll.get(ll.size() - 1), "加班");
						}
					}
				}
				indexDate = DateUtils.addDays(indexDate, 1);
			}
		}
		excelUtil.createExcelEnd(fileName);
	}

	private static Date strToDate(String dateStr, String pattern)
			throws ParseException {
		return DateUtils.parseDateStrictly(dateStr, pattern);
	}

	private static String dateToStr(Date date, String pattern) {
		return FastDateFormat.getInstance(pattern).format(date);
	}

	/**
	 * 工作日/true 休息日/false
	 * 
	 * @param date
	 * @return
	 * @throws ParseException
	 */
	private boolean isWorkDay(Date date) throws ParseException {
		if (StringUtils.isNotBlank(workTextField.getText().trim())) {
			String[] workDayStr = workTextField.getText().trim().split("/");
			for (int i = 0; i < workDayStr.length; i++) {
				Date workDay = strToDate(workDayStr[i], "yyyy-M-d");
				if (DateUtils.isSameDay(date, workDay)) {
					// 手动设置这一天为工作日
					return true;
				}
			}
		}

		if (StringUtils.isNotBlank(restTextField.getText().trim())) {
			String[] restDayStr = restTextField.getText().trim().split("/");
			for (int i = 0; i < restDayStr.length; i++) {
				Date restDay = strToDate(restDayStr[i], "yyyy-M-d");
				if (DateUtils.isSameDay(date, restDay)) {
					// 手动设置这一天为休息日
					return false;
				}
			}
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		if (cal.get(Calendar.DAY_OF_WEEK) == 1) {
			// 其余的周日都是休息日
			return false;
		}

		return true;
	}

	/**
	 * 解析Excel：把Excel数据装到dataMap中
	 * 
	 * @param filePath
	 * @return
	 */
	private Map<String, Object> parseExcel(String filePath) {
		dataMap = new HashMap<String, List<Worker>>();
		Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			POIFSFileSystem poiFile = new POIFSFileSystem(new FileInputStream(
					new File(filePath)));
			HSSFWorkbook workBook = new HSSFWorkbook(poiFile);
			HSSFSheet sheet = workBook.getSheetAt(0);
			int line = 1;
			for (Iterator<Row> rit = sheet.rowIterator(); rit.hasNext();) {
				Row row = rit.next();
				if (line != 1) {
					Worker worker = new Worker();
					String dept = getCell(row.getCell(0));
					worker.setDept(dept);
					String name = getCell(row.getCell(1));
					worker.setName(name);
					String id = getCell(row.getCell(2));
					worker.setId(id);

					String dateStr = getCell(row.getCell(3));
					if (StringUtils.isBlank(name) || StringUtils.isBlank(id)
							|| StringUtils.isBlank(dateStr)) {
						resultMap.put("flag", false);
						resultMap.put("msg", "第" + line + "行有数据为空");
						return resultMap;
					}
					// 解析时间
					try {
						Date date = DateUtils.parseDate(dateStr,
								"yyyy-M-d a h:mm:ss", "yyyy-M-d HH:mm:ss");
						worker.setDate(date);
					} catch (ParseException e) {
						resultMap.put("flag", false);
						resultMap.put("msg", "第" + line + "行“日期时间”格式错误");
						return resultMap;
					}
					String stbNo = getCell(row.getCell(4));
					worker.setStbNo(stbNo);
					String cardNo = getCell(row.getCell(7));
					worker.setCardNo(cardNo);

					if (dataMap.get(worker.getId()) == null) {
						dataMap.put(worker.getId(), new ArrayList<Worker>());
					}
					dataMap.get(worker.getId()).add(worker);
				}
				line++;
			}
		} catch (Exception e) {
			logger.error("解析Excel失败", e);
			resultMap.put("flag", false);
			resultMap.put("msg", "解析Excel失败：" + e.getMessage());
			return resultMap;
		}
		resultMap.put("flag", true);
		return resultMap;
	}

	private static String getCell(Cell cell) {
		if (cell == null)
			return "";

		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_NUMERIC:
			if (HSSFDateUtil.isCellDateFormatted(cell)) {
				double d = cell.getNumericCellValue();
				Date date = HSSFDateUtil.getJavaDate(d);
				return FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss")
						.format(date);
			}
			return cell.getNumericCellValue() + "";
		case Cell.CELL_TYPE_STRING:
			return cell.getStringCellValue();
		case Cell.CELL_TYPE_FORMULA:
			return cell.getCellFormula();
		case Cell.CELL_TYPE_BLANK:
			return "";
		case Cell.CELL_TYPE_BOOLEAN:
			return cell.getBooleanCellValue() + "";
		case Cell.CELL_TYPE_ERROR:
			return cell.getErrorCellValue() + "";
		}
		return "";
	}
}
